from PyQt5.QtWidgets import *
import threading
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QFileDialog, QMessageBox, QDockWidget, QListWidget
from PyQt5.QtGui import *
import face_recognition
import cv2
import os






class MainWindow(QTabWidget):
    # 基本配置不动，然后只动第三个界面
    def __init__(self):
        # 初始化设置
        super().__init__()
        self.setWindowTitle('基于机器学习的人脸识别系统_吃遍天小队')
        self.resize(1100, 650)
        self.setWindowIcon(QIcon("UI_images/logo.png"))
        # 要上传的图片路径
        self.up_img_name = ""
        # 要检测的图片名称
        self.input_fname = ""
        # 要检测的视频名称
        # self.source = ''
        # self.video_capture = cv2.VideoCapture(0)
        # 初始化中止事件
        self.stopEvent = threading.Event()
        self.stopEvent.clear()
        self.openfile_name=""
        # # 初始化人脸向量
        # self.known_names, self.known_encodings = self.initFaces()
        # 加载lbp检测器
        # 加载人脸识别模型
        # 初始化界面
        self.initUI()
        self.set_down()

    def initUI(self):
        # 设置字体
        font_v = QFont('楷体', 14)
        generally_font = QFont('楷体', 15)
        # 图片检测
        img_widget = QWidget()
        img_layout = QVBoxLayout()
        img_f_title = QLabel("上传人脸图像")  # 设置标题
        img_f_title.setAlignment(Qt.AlignCenter)  # 设置标题位置为居中
        img_f_title.setFont(QFont('楷体', 18))  # 设置标题字体大小
        # todo 要上传的人脸图像
        self.img_f_img = QLabel()  # 设置第一个界面上要显示的图片
        self.img_f_img.setPixmap(QPixmap("UI_images/renlian1.jpg"))  # 初始化要显示的图片
        self.img_f_img.setAlignment(Qt.AlignCenter)  # 设置图片居中
        # self.face_name = QLineEdit()  # 设置当前图片对应的人名
        img_up_btn = QPushButton("上传图片")  # 设置上传图片的按钮
        img_det_btn = QPushButton("开始检测")  # 设置开始上传的按钮
        img_up_btn.clicked.connect(self.up_img)  # 联系到相关函数
        img_det_btn.clicked.connect(self.check_recobnition)  # 连接到相关函数
        # 设置组件的样式
        img_up_btn.setFont(generally_font)
        img_det_btn.setFont(generally_font)
        img_up_btn.setStyleSheet("QPushButton{color:white}"
                                 "QPushButton:hover{background-color: rgb(2,110,180);}"
                                 "QPushButton{background-color:rgb(48,124,208)}"
                                 "QPushButton{border:2px}"
                                 "QPushButton{border-radius:5px}"
                                 "QPushButton{padding:5px 5px}"
                                 "QPushButton{margin:5px 5px}")
        img_det_btn.setStyleSheet("QPushButton{color:white}"
                                  "QPushButton:hover{background-color: rgb(2,110,180);}"
                                  "QPushButton{background-color:rgb(48,124,208)}"
                                  "QPushButton{border:2px}"
                                  "QPushButton{border-radius:5px}"
                                  "QPushButton{padding:5px 5px}"
                                  "QPushButton{margin:5px 5px}")
        # 将组件添加到布局上，然后设置主要的widget为当前的布局
        img_layout.addWidget(img_f_title)
        img_layout.addWidget(self.img_f_img)
        # img_layout.addWidget(self.face_name)
        img_layout.addWidget(img_up_btn)
        img_layout.addWidget(img_det_btn)
        img_widget.setLayout(img_layout)


        self.addTab(img_widget, "上传人脸")
        # self.addTab(video_widget, '视频检测')
        # self.addTab(about_widget, '关于')
        self.setTabIcon(0, QIcon('UI_images/图片.png'))
        # self.setTabIcon(1, QIcon('UI_images/图片.png'))
        # self.setTabIcon(1, QIcon('UI_images/直播.png'))
        # self.setTabIcon(2, QIcon('UI_images/logo_about.png'))

    def up_img(self):
        # 打开文件选择框
        self.openfile_name = QFileDialog.getOpenFileName(self, '选择文件', '', 'Image files(*.jpg , *.png)')
        # 获取上传的文件名称
        self.img_name = self.openfile_name[0]
        if self.img_name == '':
            pass
        else:
            # 上传之后显示并做归一化处理
            src_img = cv2.imread(self.img_name)
            src_img_height = src_img.shape[0]
            src_img_width = src_img.shape[1]
            target_img_height = 400
            ratio = target_img_height / src_img_height
            target_img_width = int(src_img_width * ratio)
            # 将图片统一处理到高为400的图片，方便在界面上显示
            target_img = cv2.resize(src_img, (target_img_width, target_img_height))
            cv2.imwrite("UI_images/tmp/toup.jpg", target_img)
            self.img_f_img.setPixmap(QPixmap("UI_images/tmp/toup.jpg"))
            self.up_img_name = "UI_images/tmp/toup.jpg"

    def check_recobnition(self):
        import joblib
        from PIL import Image
        import numpy as np
        import pandas as pd
        model = joblib.load(open('my_first_model4.pkl', 'rb'))
        x = Image.open(self.img_name)
        image = np.array(x, "f")  ###灰度值转化成numpy数组（二维）

        image_arr = np.array(image, "f")
        # print(image_arr.shape)
        x = np.expand_dims(image_arr, 0)
        # print(x.shape)
        x_image_arr = np.array(x, "f")  ###灰度值转化成numpy数组(二维)
        x_flat_arr = x_image_arr.ravel()
        x_flat_arr = x_flat_arr.reshape(-1, 1)
        x_flat_arr = x_flat_arr.T
        # print(x_flat_arr.shape)
        output_predict = model.predict(x_flat_arr)
        # print(output_predict)
        import numpy as np
        import cv2
        # names = ['ljj', 'xwh', 'uzi', 'saonan', 'curry', 'lyf', 'ymi', 'yming', 'zjl', 'hjy', 'lyc', 'zwy', 'hp']
        names=['bjt','ldh','lhr','lxl','13','14','pyx','wbq','17','my','wj','cl','xz','ymi','yming','zgr','zj','zk','zjd','zjl','zxc','curry','dc','dzq','dlrb','gxt','hxm','jl']
        # 实例化人脸分类器
        face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')  # xml来源于资源文件。
        # 读取测试图片
        img = cv2.imread(self.img_name, cv2.IMREAD_COLOR)
        width, high, channel = img.shape
        width_new, high_new = (256, 256)

        img_crop = img[width - width_new:, 256:256, :]
        print(img_crop.shape)

        # 将原彩色图转换成灰度图
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # 开始在灰度图上检测人脸，输出是人脸区域的外接矩形框
        faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=1)
        # 遍历人脸检测结果
        for (x, y, w, h) in faces:
            # 在原彩色图上画人脸矩形框
            cv2.rectangle(img, (x, y), (x + w, y + h), (0, 256, 0), 2)
        # 显示画好矩形框的图片
        cv2.namedWindow('faces', cv2.WINDOW_AUTOSIZE)
        font = cv2.FONT_HERSHEY_DUPLEX
        cv2.putText(img, str(names[output_predict[0]]), (x + 5, y + 5), font, 1.0, (0, 0, 255), 1)
        self.save_path="my_2t.jpg"
        # cv2.imshow('faces', img)
        cv2.imwrite(self.save_path,img)
        # 等待退出键
        # cv2.waitKey(0)
        # 销毁显示窗口
        cv2.destroyAllWindows()

        src_img = cv2.imread(self.save_path)
        src_img_height = src_img.shape[0]
        src_img_width = src_img.shape[1]
        target_img_height = 400
        ratio = target_img_height / src_img_height
        target_img_width = int(src_img_width * ratio)
        # 将图片统一处理到高为400的图片，方便在界面上显示
        target_img = cv2.resize(src_img, (target_img_width, target_img_height))
        cv2.imwrite("UI_images/tmp/toup1.jpg", target_img)
        self.img_f_img.setPixmap(QPixmap("UI_images/tmp/toup1.jpg"))
        self.up_img_name = "UI_images/tmp/toup1.jpg"

    def closeEvent(self, event):
        reply = QMessageBox.question(self,
                                     '退出',
                                     "是否要退出程序？",
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.close()
            event.accept()
        else:
            event.ignore()

    # def open(self):
    #     # 选择录像文件进行读取
    #     mp4_fileName, fileType = QFileDialog.getOpenFileName(self, 'Choose file', '', '*.mp4')
    #     if mp4_fileName:
    #         # 启动录像文件读取得线程并在画面上实时显示
    #         self.source = mp4_fileName
    #         self.video_capture = cv2.VideoCapture(self.source)
    #         th = threading.Thread(target=self.display_video)
    #         th.start()

    # def open_local(self):
    #     # 选择录像文件进行读取
    #     mp4_filename = 0
    #     self.source = mp4_filename
    #     # 读取摄像头进行实时得显示
    #     self.video_capture = cv2.VideoCapture(self.source)
    #     th = threading.Thread(target=self.display_video)
    #     th.start()

    # 退出进程
    def close(self):
        # 点击关闭按钮后重新初始化界面
        self.stopEvent.set()
        self.set_down()

    def set_down(self):
        # self.video_capture.release()
        cv2.destroyAllWindows()
        # self.DisplayLabel.setPixmap(QPixmap("UI_images/ae862.jpg"))

if __name__ == "__main__":
    # 加载页面
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    sys.exit(app.exec_())



